use actix_cors::Cors;
use actix_web::{web, App, HttpServer, middleware::Logger};
use sea_orm::{Database, DatabaseConnection};
use tracing_subscriber;
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;

mod auth;
mod cache;
mod config;
mod controllers;
mod entities;
mod errors;
mod migrations;
mod models;
mod routes;
mod services;

use config::Config;
use cache::AppCache;
use auth::AuthService;

#[derive(OpenApi)]
#[openapi(
    paths(
        controllers::public::get_articles,
        controllers::public::get_article,
        controllers::public::get_products,
        controllers::public::get_product,
        controllers::public::get_categories,
        controllers::public::get_brands,
        controllers::public::get_languages,
    ),
    components(
        schemas(
            models::Article,
            models::ArticleTranslation,
            models::Product,
            models::ProductTranslation,
            models::Category,
            models::CategoryTranslation,
            models::Brand,
            models::BrandTranslation,
            models::Language,
            models::FilterOptions,
            models::PaginatedResponse<models::Article>,
            models::Pagination,
            models::PublicationStatus,
        )
    ),
    tags(
        (name = "Public Articles", description = "Public article endpoints"),
        (name = "Public Products", description = "Public product endpoints"),
        (name = "Public Categories", description = "Public category endpoints"),
        (name = "Public Brands", description = "Public brand endpoints"),
        (name = "Public Languages", description = "Public language endpoints"),
    ),
    info(
        title = "Multilingual Content Management API",
        description = "A multilingual article and product management system",
        version = "1.0.0",
        contact(
            name = "API Support",
            email = "support@example.com"
        )
    )
)]
struct ApiDoc;

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    // Initialize tracing
    tracing_subscriber::fmt::init();

    // Load configuration
    let config = Config::from_env().expect("Failed to load configuration");

    // Connect to database
    let db: DatabaseConnection = Database::connect(&config.database_url)
        .await
        .expect("Failed to connect to database");

    // Run migrations
    migrations::run_migrations(&db).await.expect("Failed to run migrations");

    // Initialize cache
    let cache = AppCache::new(config.cache_max_capacity, config.cache_ttl_seconds);

    // Initialize auth service
    let auth_service = AuthService::new(
        db.clone(),
        cache.clone(),
        config.oidc_issuer.clone(),
        config.oidc_client_id.clone(),
        config.jwt_secret.clone(),
    )
    .expect("Failed to initialize auth service");

    // Start HTTP server
    let server = HttpServer::new(move || {
        App::new()
            // Add CORS
            .wrap(
                Cors::default()
                    .allow_any_origin()
                    .allow_any_method()
                    .allow_any_header()
                    .supports_credentials()
            )
            // Add logging
            .wrap(Logger::default())
            // Add JWT validator
            .app_data(web::Data::new(auth_service.clone()))
            // Add shared data
            .app_data(web::Data::new(db.clone()))
            .app_data(web::Data::new(auth_service.clone()))
            .app_data(web::Data::new(cache.clone()))
            // Add Swagger UI
            .service(
                SwaggerUi::new("/swagger-ui/{_:.*}")
                    .url("/api-docs/openapi.json", ApiDoc::openapi()),
            )
            // Configure routes
            .configure(routes::configure_routes)
    })
    .bind(config.server_address())?;

    println!("🚀 Server started at http://{}", config.server_address());
    println!("📚 Swagger UI available at http://{}/swagger-ui/", config.server_address());

    server.run().await
}
